// 首先通过 import 语句引入了在 Three.js 中用于加载 GLTF 格式模型的 GLTFLoader 和用于解码 Draco 压缩数据的 DRACOLoader
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
import BaseModel from '../BaseModel';
import type Viewer from '../Viewer';

type LoadModelCallbackFn<T = any> = (arg: T) => any;

/**模型加载器 */
export default class ModelLoder {
  // ModelLoader 类定义了一个模型加载器，其中包含了一个 Three.js 的 Viewer 对象、GLTFLoader 对象和 DRACOLoader 对象。
  protected viewer: Viewer;
  private gltfLoader: GLTFLoader;
  private dracoLoader: DRACOLoader;

  constructor(viewer: Viewer, dracolPath: string = '/draco/') {
    this.viewer = viewer;
    this.gltfLoader = new GLTFLoader();
    this.dracoLoader = new DRACOLoader();

    // 总的来说，这两行代码的作用是为了在加载使用了 Draco 压缩格式的模型时，确保正确设置了解码器的路径，并且 GLTFLoader 能够顺利地使用 DRACOLoader 进行数据解码操作，从而正确加载并显示这些模型。这样可以确保应用程序能够顺利地处理使用了 Draco 压缩格式的模型数据。
    // 提供一个DracLoader实例来解码压缩网格数据
    // 没有这个会报错 dracolPath 默认放在public文件夹当中
    // 这行代码设置了 DRACOLoader 的解码器路径，指定了 DRACO 压缩数据解码器的位置。
    // 在加载使用了 Draco 压缩格式的模型时，需要指定解码器的路径，以便正确解码模型数据。
    // 参数 dracolPath 是指定的 DRACO 解码器路径，默认值为 '/draco/'，通常是指向存放 Draco 解码器文件的目录路径
    this.dracoLoader.setDecoderPath(dracolPath);
    // 这行代码将创建的 DRACOLoader 实例与 GLTFLoader 关联起来。
    //  这样做是为了在使用 GLTFLoader 加载使用了 Draco 压缩格式的模型时，能够自动调用 DRACOLoader 进行解码。
    // 通过将 DRACOLoader 实例传递给 GLTFLoader，GLTFLoader 将会在需要的时候使用 DRACOLoader 进行解码操作。
    this.gltfLoader.setDRACOLoader(this.dracoLoader);
  }

  /**模型加载到场景 */
  // loadModelToScene(url: string, callback: LoadModelCallbackFn<BaseModel>) 方法用于将指定 URL 的模型加载到场景中，并通过回调函数返回加载后的 BaseModel 对象。
  public loadModelToScene(url: string, callback: LoadModelCallbackFn<BaseModel>) {
    this.loadModel(url, model => {
      this.viewer.scene.add(model.object);
      callback && callback(model);
    });
  }

  // 首先调用 loadModel() 方法加载模型，然后将加载后的模型对象添加到 Viewer 的场景中，并通过回调函数返回 BaseModel 对象。
  private loadModel(url: string, callback: LoadModelCallbackFn<BaseModel>) {
    this.gltfLoader.load(url, gltf => {
      const baseModel = new BaseModel(gltf, this.viewer);
      callback && callback(baseModel);
    });
  }
}
